package com.leboncoin.batch;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;


import com.leboncoin.bean.ClassifiedBean;
import com.leboncoin.bean.SearchItemBean;
import com.leboncoin.bean.SubscriptionBean;
import com.leboncoin.html.LeboncoinHtmlClassifiedDetail;
import com.leboncoin.html.LeboncoinHtmlSearchResult;
import com.leboncoin.http.HttpManager;
import com.leboncoin.xml.ConfigManager;
import com.leboncoin.xml.ConfigManager.TAG_NAMES;
import java.io.UnsupportedEncodingException;
import java.util.logging.Level;

/**
 * Base class for leboncoin search
 *
 * @author ben
 */
public class CommonSearch {

    protected final static Logger logger = Logger.getLogger(CommonSearch.class.getName());
    protected static CommonSearch instance;
    public final static String LEBONCOIN_ROOT_URL = "http://leboncoin.fr";

    private CommonSearch() {
    }

    public static CommonSearch getInstance() {
        if (instance == null) {
            instance = new CommonSearch();
        }
        return instance;
    }

    /**
     * Search classified from subscriptionBean
     *
     * @param daySearch
     * @param subscriptionBean
     * @throws Exception
     */
    public void searchFromSubscription(Boolean daySearch, SubscriptionBean subscriptionBean) throws Exception {

        logger.log(Level.INFO, "Abonnement: {0}", subscriptionBean.getName());

        for (SearchItemBean searchItemBean : subscriptionBean.getSearchItems()) {

            logger.log(Level.INFO, "Category:{0}", searchItemBean.getSearchCategory());
            logger.log(Level.INFO, "Text:{0}", searchItemBean.getSearchText());

            List<ClassifiedBean> classifieds = searchFromSearchItem(searchItemBean, daySearch);

            searchItemBean.setSearchResults(classifieds);
        }
    }

    /**
     * Search classifieds from given searchItemBean
     *
     * @param searchItemBean
     * @param daySearch
     * @return
     * @throws java.io.UnsupportedEncodingException
     */
    protected List<ClassifiedBean> searchFromSearchItem(SearchItemBean searchItemBean, Boolean daySearch) throws UnsupportedEncodingException {

        List<ClassifiedBean> classifieds = new ArrayList<>();
        StringBuilder url = new StringBuilder(LEBONCOIN_ROOT_URL);
        String urlPart = ConfigManager.CATEGORIES.get(searchItemBean.getSearchCategory());
        url.append("/").append(urlPart).append("/offres/");

        url.append(searchItemBean.getSearchLocation().toString()).append("/");
        
        url.append("?f=a&th=1");
        if (searchItemBean.getSearchText() != null && !searchItemBean.getSearchText().isEmpty()){
            String parameterName = TAG_NAMES.SEARCH_TEXT.getUrlParameter();
            String parameterValue = searchItemBean.getSearchTextUrlEncoded();
            url.append("&").append(parameterName).append("=").append(parameterValue);
        }

        if (searchItemBean.getPriceMin() != null){
            String parameterName = TAG_NAMES.PRICE_MIN.getUrlParameter();
            String parameterString = searchItemBean.getPriceMin().toString();
            Integer parameterValue = ConfigManager.getInstance(null).getPrice(parameterString);
            if (parameterValue == null) {
                throw new RuntimeException("Impossible to find price min "+parameterString);
            }
            url.append("&").append(parameterName).append("=").append(parameterValue);
        }

        if (searchItemBean.getPriceMax() != null){
            String parameterName = TAG_NAMES.PRICE_MAX.getUrlParameter();
            String parameterString = searchItemBean.getPriceMax().toString();
            Integer parameterValue = ConfigManager.getInstance(null).getPrice(parameterString);
            if (parameterValue == null) {
                throw new RuntimeException("Impossible to find price min "+parameterString);
            }
            url.append("&").append(parameterName).append("=").append(parameterValue);
        }

        // Autres options a cocher
        if (searchItemBean.getCheckBoxList().size() > 0) {
            for (String checkBoxId : searchItemBean.getCheckBoxList()) {
                url.append("&").append(checkBoxId).append("=1");
            }
        }

        if (searchItemBean.getZipCodes() != null) {
            for (String zipCode:searchItemBean.getZipCodes()) {
                List<ClassifiedBean> tmpResult = processSearchItemFromUrl(url.toString()+"&location="+zipCode, searchItemBean, daySearch);
                classifieds.addAll(tmpResult);
            }
        } else {
            classifieds = processSearchItemFromUrl(url.toString(), searchItemBean, daySearch);
        }
        return classifieds;
    }
    
    protected List<ClassifiedBean> processSearchItemFromUrl(String url, SearchItemBean searchItemBean, Boolean daySearch) {

        logger.log(Level.INFO, "Search URL : {0}", url);

        String htmlSource = HttpManager.getHtmlPage(url);

        LeboncoinHtmlSearchResult htmlPage = new LeboncoinHtmlSearchResult(htmlSource);
        List<ClassifiedBean> classifieds = htmlPage.getClassifiedList(daySearch);

        for (ClassifiedBean classifiedBean : classifieds) {

            // Link classified to search item
            classifiedBean.setSearchItemBean(searchItemBean);

            // Get detail page to populate price and images
            String htmlDetailSource = null;
            try {
                htmlDetailSource = HttpManager.getHtmlPage(classifiedBean.getLink());
            } catch (Exception e) {
                logger.severe(e.getMessage());
            }
            if (htmlDetailSource != null) {
                try {
                    LeboncoinHtmlClassifiedDetail htmlDetailPage = new LeboncoinHtmlClassifiedDetail(htmlDetailSource);
                    htmlDetailPage.populatePrice(classifiedBean);
                    htmlDetailPage.populateImages(classifiedBean);
                } catch (Exception e) {
                    logger.log(Level.SEVERE, "Impossible to populate image and price from source", e);
                    logger.severe(htmlDetailSource);
                }
            }

        }
        return classifieds;
    }
    
}
